package com.ben.utils.ext

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.ben.utils.flow.GlobalFlowScope
import kotlinx.coroutines.*

/**
 * Author: bin.yang
 * Maintainer: bin.yang
 * Date: 2020/3/11
 * Copyright: 2020 Inc. All rights reserved.
 * Desc:
 */

fun launchGlobalMain(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
    return GlobalFlowScope.scope.launchMain(delayTime, func)
}

fun launchGlobalIO(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
    return GlobalFlowScope.scope.launchIO(delayTime, func)
}

fun launchGlobalDefault(delayTime: Long = 0L, func: suspend () -> Unit): Job {
    return GlobalFlowScope.scope.launch(Dispatchers.Default) {
        if (delayTime != 0L) {
            delay(delayTime)
        }
        func()
    }
}

fun CoroutineScope.launchMain(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
    return launch(Dispatchers.Main) {
        if (delayTime != 0L) {
            delay(delayTime)
        }
        func()
    }
}

fun CoroutineScope.launchIO(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
    return launch(Dispatchers.IO) {
        if (delayTime != 0L) {
            delay(delayTime)
        }
        func()
    }
}

fun CoroutineScope.launchDefault(
    delayTime: Long = 0L,
    func: suspend CoroutineScope.() -> Unit
): Job {
    return launch(Dispatchers.Default) {
        if (delayTime != 0L) {
            delay(delayTime)
        }
        func()
    }
}

suspend fun CoroutineScope.withContextMain(
    delayTime: Long = 0L,
    func: suspend CoroutineScope.() -> Unit
) {
    withContext(Dispatchers.Main) {
        if (delayTime != 0L) {
            delay(delayTime)
        }
        func()
    }
}

suspend fun CoroutineScope.withContextIO(
    delayTime: Long = 0L,
    func: suspend CoroutineScope.() -> Unit
) {
    withContext(Dispatchers.IO) {
        if (delayTime != 0L) {
            delay(delayTime)
        }
        func()
    }
}

fun ViewModel.launchMain(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
    return viewModelScope.launchMain(delayTime, func)
}

fun ViewModel.launchIO(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
    return viewModelScope.launchIO(delayTime, func)
}

fun ViewModel.launchDefault(delayTime: Long = 0L, func: suspend CoroutineScope.() -> Unit): Job {
    return viewModelScope.launchDefault(delayTime, func)
}

/**
 * 阻塞函数，等待返回一个结果
 * @param timeOut 加载超时时间
 * @param block
 */
suspend fun <T> blockForResult(
    timeOut: Long = 10 * 1000L,
    block: (CancellableContinuation<T>) -> Unit
) =
    withTimeoutOrNull(timeOut) { suspendCancellableCoroutine<T> { block(it) } }
